import queue
import random
import threading
from typing import Dict, Any, List

import numpy as np

import re
from typing import Optional, Union, Sequence

import json

from agentscope.message import Msg
from agentscope.agents import AgentBase
from agentscope.models import ModelResponse
from agentscope.parsers import MarkdownJsonDictParser
MEMORY_LENGTH = 5
def parse_func(response: ModelResponse) -> ModelResponse:
    text = response.text  # 大模型中的content

    """
        解析 Agent 的回复，提取 reasoning 和 belief

        :param response: Agent 的回复
        :return: 包含 reasoning 和 belief 的字典
        """
    # 使用正则表达式提取 <reasoning> 和 <belief> 内容
    #reasoning_match = re.search(r"<reasoning>(.*?)</reasoning>", text, re.DOTALL)
    content_match = re.search(r"<content>(.*?)</content>", text,re.DOTALL)
    belief_match = re.search(r"<belief>(.*?)</belief>", text)

    if not content_match or not belief_match:
        raise ValueError("Invalid response format: missing <reasoning> or <belief>")

    #reasoning = reasoning_match.group(1).strip()
    content = content_match.group(1).strip()
    belief = float(belief_match.group(1).strip())

    text_dic={
        #"reasoning": reasoning,
        "content":content,
        "belief": belief
    }
    return ModelResponse(raw=text_dic)
class Agent(AgentBase):
    # 全局人名列表，用于确保不重复

    def __init__(self,
                 name: str,
                 model_config_name: str,
                 long_term="",
                 sys_prompt="",
                 topic="",
                 ) -> None:
        super().__init__(
            name=name,
            sys_prompt=sys_prompt,
            model_config_name=model_config_name,
        )
        self.long_term =long_term
        """
                初始化一个智能体（Agent）
        
                :param agent_id: 智能体的唯一标识符
                """
        # self.sys_prompt=self.generate_basic_prompt(pro)
        self.name = name
        self.topic=topic
        self.belief = self._initialize_belief()  # 初始信念值 [-2, 2]
        self.neighbors = []  # 邻居节点（其他智能体）

        self.receive_queue = queue.Queue(maxsize=100)  # 线程安全接收队列
        self.lock = threading.Lock()  # 处理队列时的锁

    parser = MarkdownJsonDictParser(
        content_hint='{"content": "你的互动...", "belief": "新的信念值（范围：-2到2）"}',
        required_keys=["content", "belief"],
    )

    def _initialize_belief(self) -> float:
        """
        初始化智能体的信念值，范围 [-2, 2]

        :return: 初始信念值
        """
        # return round(random.uniform(-2, 2), 2)
        return 0

    def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
        if self.memory:
            self.memory.add(x)  # 别人给他的消息也会塞到mempry里
        prompt_str = self.sys_prompt
        prompt_str +=self.topic
        # 添加反思和更新信念的指示
        prompt_str += (
            "信念值变化规则："
            "信念值通常是一个范围在 -2 到 2 之间的数值，表示代理对某个话题的支持或反对程度。具体含义如下："
            """-2：完全反对，强烈不赞同。
            -1：轻度反对，不完全同意。
            0：中立，不偏向任何一方。
            1：轻度支持，同意对方观点。
            2：完全支持，强烈赞同。"""
            "- 外向性（E）较高的代理可能会更容易被他人的观点影响，因此信念值可能会在互动后增加。"
            "- 神经质（N）较高的代理更容易对负面反馈产生反应，导致信念值发生较大变化。"
            "\n请根据你的性格特质和之后的互动，反思并更新你对当前话题的信念。请按照以下格式回答：\n"
        )
        prompt_str+=self.parser.format_instruction
        sys_msg_hint = Msg("system", prompt_str, role="system")  # 这个会变成response的prompt但不会写入到system

        agent_memory= self.memory.get_memory()# 返回的list是一个受保护类型的msg列表
        prompt = self.model.format(  # 一个合并de动作
            sys_msg_hint,  # 背景prompt
            agent_memory[0-MEMORY_LENGTH:]
        )  # 根据记忆内容进行判断
        #print(prompt)
        response = None
        try:
            response = self.get_response_with_retries(prompt)
            self.belief=float(response['belief'])
        except Exception as final_error:
            print("所有尝试均失败。错误信息:", final_error)

        self.speak(
            Msg(
                self.name,
                response,  # 这里如果生成的是json可以用json.dump
                role="assistant",
            ),
        )

        if self.memory:  # 启用记忆模块就加进来把自己说的历史输出
            self.memory.add(Msg(self.name, response, role="system"))
        #TODO 遗忘机制

        # Hide thought from the response
        return Msg(self.name, response, role="system")

    def get_response_with_retries(self, prompt, max_retries=5):
        """
        尝试调用 self.model 并获取 .raw 属性。如果发生错误，则重试，直到达到最大重试次数。

        :param prompt: 提示内容
        :param parse_func: 解析函数
        :param max_retries: 最大重试次数（默认3次）
        :return: response.raw
        :raises: 最后一次尝试时抛出的异常
        """
        attempt = 0
        while attempt < max_retries:
            try:
                response = self.model(
                    prompt
                )
                parsed_response = self.parser.parse(response)
                return parsed_response.parsed  # 成功，返回结果
            except Exception as e:
                attempt += 1
                print(f"尝试第 {attempt} 次失败。错误信息: {e}")
                if attempt == max_retries:
                    print("达到最大重试次数，抛出异常。")
                    raise  # 达到最大重试次数，重新抛出异常
                else:
                    print("正在重试...")

    def __repr__(self):
        """
        打印智能体的基本信息
        """
        return (f"Agent(ID={self.id}, Name={self.profile['name']}, "
                f"Belief={self.belief:.2f}, Neighbors={len(self.neighbors)})")

#TODO 更新记忆
    def update_memory_and_dialog(self, new_memory: str):
        # 更新记忆字符串
        self.long_term = new_memory
